#ifndef LOGGER_HPP_
#define LOGGER_HPP_

#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <vector>

class Logger {
public:
  	enum Level {
    		ERROR,
    		WARNING,    
    		INFO
  	};
private: 
	Level level;
  	FILE* file;
  	std::vector<std::string> mesBuf;

  	Logger() { 
		file = NULL;
	}

  	~Logger() {
    		if (file != NULL) {
      			flush();
    			fclose(file);
    		}
  	}

  	Logger(const Logger& other);
  	Logger& operator = (const Logger& other);
public:
  	static Logger& getInstance() {
    		static Logger logger;
    		return logger;
  	}

  	void setFile(const char *path) {
    		assert(path != NULL);
    		file = fopen(path, "w+");
    		mesBuf.reserve(8);
  	}

  	void log(Level level, const char* format, ...) {
    		assert(file != NULL);
    		assert(format != NULL);

    		char buffer[1024];
    
    		va_list args;
    		va_start(args, format);
    		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
    		va_end(args);
    
    		std::string entry = convertLevelToString(level);
    		entry.append(buffer);
    		mesBuf.push_back(entry);
  	}

  	void flush() {
    		assert(file != NULL);
    		for (unsigned int i = 0; i < mesBuf.size(); ++i) {
      			fprintf(file, "%s\n", mesBuf[i].c_str());
    		}
    		mesBuf.clear();
  	}

private:
  	static std::string convertLevelToString(Level level) {
    		if (level ==  INFO) {
      			return "INFO : ";
    		} else if (level == WARNING) {
      			return "WARNING : ";
    		} else if (level == ERROR) {
      			return "ERROR : ";
    		}
		exit(1);
  	}
};

#endif // LOGGER_HPP_

